<!DOCTYPE html>
<html>
<head>
    <title>Spherical Pendulum Diagram</title>
</head>
<body>

<canvas id="sphericalPendulumCanvas" width="400" height="400" style="border: 1px solid #ccc;"></canvas>

<script>
    const canvas = document.getElementById('sphericalPendulumCanvas');
    const ctx = canvas.getContext('2d');

    // --- Style and Configuration ---
    ctx.lineWidth = 2;
    ctx.strokeStyle = 'black';
    ctx.fillStyle = 'black';
    ctx.font = 'italic 18px Times New Roman';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';

    // --- Drawing Parameters ---
    const origin = { x: 200, y: 110 };
    const l = 120; // Length of the string in pixels
    const theta = Math.PI / 4.5; // Angle theta in radians (approx. 40 degrees)

    // --- Calculated Coordinates ---
    // Position of the mass
    const massPos = {
        x: origin.x + l * Math.sin(theta),
        y: origin.y + l * Math.cos(theta)
    };
    // Center and radii of the elliptical path (for perspective)
    const pathCenter = { x: origin.x, y: massPos.y };
    const pathRadiusX = l * Math.sin(theta);
    const pathRadiusY = pathRadiusX * 0.3;

    // Helper function to draw an arrowhead on a line
    function drawArrowhead(toX, toY, angle) {
        const headLength = 10;
        ctx.beginPath();
        ctx.moveTo(toX, toY);
        ctx.lineTo(toX - headLength * Math.cos(angle - Math.PI / 6), toY - headLength * Math.sin(angle - Math.PI / 6));
        ctx.moveTo(toX, toY);
        ctx.lineTo(toX - headLength * Math.cos(angle + Math.PI / 6), toY - headLength * Math.sin(angle + Math.PI / 6));
        ctx.stroke();
    }

    // --- Drawing Sequence ---

    // 1. Draw Axes
    // z-axis (vertical)
    ctx.beginPath();
    ctx.moveTo(origin.x, origin.y + 40);
    ctx.lineTo(origin.x, origin.y - 90);
    ctx.stroke();
    drawArrowhead(origin.x, origin.y - 90, -Math.PI / 2);
    ctx.fillText('z', origin.x - 15, origin.y - 90);

    // x-axis (horizontal)
    ctx.beginPath();
    ctx.moveTo(origin.x - 40, origin.y);
    ctx.lineTo(origin.x + 160, origin.y);
    ctx.stroke();
    drawArrowhead(origin.x + 160, origin.y, 0);
    ctx.fillText('x', origin.x + 175, origin.y);

    // 2. Draw Dashed Lines and Path
    ctx.save();
    ctx.setLineDash([4, 4]);

    // Vertical helper line for angle
    ctx.beginPath();
    ctx.moveTo(origin.x, origin.y);
    ctx.lineTo(pathCenter.x, pathCenter.y);
    ctx.stroke();

    // Horizontal helper line (radius)
    ctx.beginPath();
    ctx.moveTo(pathCenter.x, pathCenter.y);
    ctx.lineTo(massPos.x, massPos.y);
    ctx.stroke();

    // Dashed circular path (ellipse for perspective)
    ctx.beginPath();
    ctx.ellipse(pathCenter.x, pathCenter.y, pathRadiusX, pathRadiusY, 0, 0, 2 * Math.PI);
    ctx.stroke();

    ctx.restore(); // Reset to solid lines

    // 3. Draw Pendulum String and label 'l'
    ctx.beginPath();
    ctx.moveTo(origin.x, origin.y);
    ctx.lineTo(massPos.x, massPos.y);
    ctx.stroke();
    ctx.fillText('l', origin.x + pathRadiusX / 2 + 10, origin.y + (massPos.y - origin.y) / 2);

    // 4. Draw the Mass bob and label 'm'
    ctx.beginPath();
    ctx.arc(massPos.x, massPos.y, 5, 0, 2 * Math.PI);
    ctx.fill();
    ctx.fillText('m', massPos.x + 20, massPos.y);
    
    // 5. Draw velocity arrow from mass
    ctx.beginPath();
    ctx.moveTo(massPos.x, massPos.y);
    ctx.lineTo(massPos.x + 60, massPos.y);
    ctx.stroke();
    drawArrowhead(massPos.x + 60, massPos.y, 0);

    // 6. Draw Angle Arc and label 'θ'
    ctx.beginPath();
    ctx.arc(origin.x, origin.y, 30, Math.PI / 2, Math.PI / 2 + theta);
    ctx.stroke();
    ctx.fillText('θ', origin.x + 22, origin.y + 30);

    // 7. Draw Rotation Arrow
    const rotArrowY = pathCenter.y + pathRadiusY + 15;
    const rotArrowStartX = origin.x - 60;
    const rotArrowEndX = origin.x + 40;
    const rotArrowControlX = origin.x - 10;
    const rotArrowControlY = rotArrowY + 15;
    ctx.beginPath();
    ctx.moveTo(rotArrowStartX, rotArrowY);
    ctx.quadraticCurveTo(rotArrowControlX, rotArrowControlY, rotArrowEndX, rotArrowY);
    ctx.stroke();
    const endTangentAngle = Math.atan2(rotArrowY - rotArrowControlY, rotArrowEndX - rotArrowControlX);
    drawArrowhead(rotArrowEndX, rotArrowY, endTangentAngle);

    // 8. Draw 'φ̇' (phi-dot) Label
    const phiPos = { x: origin.x + 65, y: massPos.y + 25 };
    ctx.fillText('φ', phiPos.x, phiPos.y);
    // Draw the dot above 'φ'
    ctx.beginPath();
    ctx.arc(phiPos.x, phiPos.y - 12, 1.5, 0, 2 * Math.PI);
    ctx.fill();

    // 9. Draw Figure Caption
    ctx.font = 'bold 16px sans-serif';
    ctx.fillText('Fig. 2.14.', canvas.width / 2, canvas.height - 25);

</script>

</body>
</html>